昨天介紹了有關 checkpoint 檔的存取,今天來介紹 pb 檔,幫大家複習一下,pb檔和checkpoint的差別主要是 pb 檔使用時機是你模型已確定,準備匯出應用時,普遍會存的檔案格式。
不像 checkpoint 需要 session,pb 檔在你建完節點網路時,就可以保存。
input_node = tf.placeholder(shape=[None, 100, 100, 3], dtype=tf.float32)
net = tf.layers.conv2d(input_node, 32, (3, 3), strides=(2, 2), padding='same', name='conv_1')
net = tf.layers.conv2d(net, 32, (3, 3), strides=(1, 1), padding='same', name='conv_2')
net = tf.layers.conv2d(net, 64, (3, 3), strides=(2, 2), padding='same', name='conv_3')
tf.io.write_graph(tf.get_default_graph(), "../pb/", "model.pb", as_text=False)
除了 pb 檔,你也可以存成 pbtxt 檔,好處是你可以用文字編輯器看格式。
tf.io.write_graph(tf.get_default_graph(), "../pb/", "model.pbtxt", as_text=True)
pbtxt 某部分txt格式:
node {
name: "Placeholder"
op: "Placeholder"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "shape"
value {
shape {
dim {
size: -1
}
dim {
size: 100
}
dim {
size: 100
}
dim {
size: 3
}
}
}
}
}
node {
name: "conv_1/kernel/Initializer/random_uniform/shape"
op: "Const"
attr {
key: "_class"
value {
list {
s: "loc:@conv_1/kernel"
}
}
}
attr {
key: "dtype"
value {
type: DT_INT32
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_INT32
tensor_shape {
dim {
size: 4
}
}
tensor_content: "\003\000\000\000\003\000\000\000\003\000\000\000 \000\000\000"
}
}
}
}
但是要注意的是,pbtxt比較佔空間,如果要應用還是建議存成binary的pb檔(即.pb)。
接下來有個問題,這樣的 pb 檔只能算是空殼,因為他只有網路架構,但是裡面沒有任何權重值啊!沒錯,所以這邊我來示範如何將權重一起保存進 pb 檔,一樣我們必須先 init 權重初始值。
再來我們需要 tf.graph_util.convert_variables_to_constants(),來封存權重值,要帶進去的參數很簡單,session、graph的定義和你的 output 節點名稱,最基本的只需要這三樣,拿到封存的 graph 後 (frozen_graph),就可以保存下來,這邊一樣暫存成 pb 和 pbtxt 兩種格式。
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
sess.run(tf.local_variables_initializer())
frozen_graph = tf.graph_util.convert_variables_to_constants(
sess, tf.get_default_graph().as_graph_def(), ['conv_3/BiasAdd'])
tf.io.write_graph(frozen_graph, "../pb/", "frozen_model.pb", as_text=False)
tf.io.write_graph(frozen_graph, "../pb/", "frozen_model.pbtxt", as_text=True)
從檔案大小來看,你的 pb 因為多了權重值變肥了,你也可以比對兩者 pbtxt,看看是多了哪些變數。
可以觀察到 frozen_model.pbtxt 的 conv_1/kernel 多了 tensor_content 的權重值:
最後,有個很重要的觀念,上面 tf.graph_util.convert_variables_to_constants(),我們有指定 output 的節點,tensorflow 會根據這個節點往前面推測,總共要把哪些 node 保存下來,詳細的內容我會在之後 optimze 篇章再做更詳細的介紹。
有此可知,今天當你拿到一份 pb 檔時,你無法確定這個 pb 檔是已含權重或未含權重的模型檔,你必須讀取後才能得知,所以帶有權重的 pb 檔,我們習慣在名稱前多加 frozen 前綴來區別。
大家好, 我想把 .pb 轉成 .pbtxt, 程式碼如下:
import tensorflow as tf
from tensorflow.python.platform import gfile
def convert_pb_to_pbtxt(filename):
with tf.io.gfile.GFile(filename, 'rb') as f:
graph_def = tf.compat.v1.GraphDef()
graph_def.ParseFromString(f.read())
tf.import_graph_def(graph_def, name='')
tf.train.write_graph(graph_def, './', 'protobuf.pbtxt', as_text=True)
return
filename = 'efficientnet-lite4-11.pb'
convert_pb_to_pbtxt(filename);
運行時遇到如下的問題:
D:\download\onnx\onnx_2_pb\efficientNet>python convert_to_bptxt.py
2021-02-22 11:44:21.746474: W tensorflow/stream_executor/platform/default/dso_loader.cc:55] Could not load dynamic library 'cudart64_100.dll'; dlerror: cudart64_100.dll not found
2021-02-22 11:44:21.748660: I tensorflow/stream_executor/cuda/cudart_stub.cc:29] Ignore above cudart dlerror if you do not have a GPU set up on your machine.
Traceback (most recent call last):
File "C:\Users\User\AppData\Local\Programs\Python\Python37\lib\site-packages\tensorflow_core\python\framework\importer.py", line 501, in _import_graph_def_internal
graph._c_graph, serialized, options) # pylint: disable=protected-access
tensorflow.python.framework.errors_impl.InvalidArgumentError: Node 'Softmax:0': Node name contains invalid characters
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "convert_to_bptxt.py", line 15, in
convert_pb_to_pbtxt(filepath);
File "convert_to_bptxt.py", line 9, in convert_pb_to_pbtxt
tf.import_graph_def(graph_def, name='')
File "C:\Users\User\AppData\Local\Programs\Python\Python37\lib\site-packages\tensorflow_core\python\util\deprecation.py", line 507, in new_func
return func(*args, **kwargs)
File "C:\Users\User\AppData\Local\Programs\Python\Python37\lib\site-packages\tensorflow_core\python\framework\importer.py", line 405, in import_graph_def
producer_op_list=producer_op_list)
File "C:\Users\User\AppData\Local\Programs\Python\Python37\lib\site-packages\tensorflow_core\python\framework\importer.py", line 505, in _import_graph_def_internal
raise ValueError(str(e))
ValueError: Node 'Softmax:0': Node name contains invalid characters
D:\download\onnx\onnx_2_pb\efficientNet>
主要是:ValueError: Node 'Softmax:0': Node name contains invalid characters
我的python 版本是:
D:\download\onnx\onnx_2_pb\efficientNet>python --version
Python 3.7.8
tensorflow 版本是:
D:\download\onnx\onnx_2_pb\efficientNet>pip show tensorflow
Name: tensorflow
Version: 1.15.0
Summary: TensorFlow is an open source machine learning framework for everyone.
Home-page: https://www.tensorflow.org/
Author: Google Inc.
Author-email: packages@tensorflow.org
License: Apache 2.0
Location: c:\users\user\appdata\local\programs\python\python37\lib\site-packages
Requires: grpcio, google-pasta, opt-einsum, astor, termcolor, wrapt, gast, protobuf, numpy, absl-py, six, keras-applications, tensorflow-estimator, tensorboard, wheel, keras-preprocessing
Required-by:
想請教 這是什麼問題呢? 有什麼解決的方法呢?
Regards,
錯誤是 ValueError: Node 'Softmax:0': Node name contains invalid characters
似乎是設計網路最後的softmax取名有問題
你有用中文或奇怪的標點符號嗎?
你好
沒有, 這份.pb 是用 onnx-tf 從 onnx 轉出的, 如果onnx 原始就用這種命名 : xxxx:0, 或是 xxxx:1 , 就會在
tf.import_graph_def(graph_def, name='')
這一行 報錯.
看起來像是 ':' 造成的.